#ifndef __TANSIGNALSLOT_H__
#define __TANSIGNALSLOT_H__

#ifdef __cplusplus
#include <list>
namespace Tan
{
	template <typename Receiver, typename ...Args>
	using tan_slot_function = void(Receiver::*)(Args...);

	template <typename ...Args>
	struct TanSlot { virtual void run(Args...) = 0; };

	template <typename Receiver, typename ...Args>
	struct TanSlotImpl : public TanSlot<Args...> {
		virtual void run(Args... args) override final { (receiver->*slot_func)(args...); }

		Receiver* receiver;
		tan_slot_function<Receiver, Args...> slot_func;
	};

	template <typename ...Args>
	struct TanSignal {
		void emit(Args... args) { for (TanSlot<Args...>* slot : slots) slot->run(args...); }
		~TanSignal() { for (TanSlot<Args...>* slot : slots) delete slot; }

		std::list<TanSlot<Args...>*> slots;
	};

	template <typename SIGNAL, typename Receiver, typename ...Args>
	void connect(SIGNAL&& signal, Receiver* receiver, tan_slot_function<Receiver, Args...> slot) {
		TanSlotImpl<Receiver, Args...>* slot_impl = new TanSlotImpl<Receiver, Args...>;
		slot_impl->receiver = receiver;
		slot_impl->slot_func = slot;
		signal.slots.push_back((TanSlot<Args...>*)slot_impl);
	}

	template <typename SIGNAL, typename Receiver>
	void disconnect(SIGNAL&& signal, Receiver* receiver) {
		for (auto iter = signal.slots.begin(); iter != signal.slots.end();) {
			TanSlotImpl<Receiver, void*>* slot_impl = (TanSlotImpl<Receiver, void*>*)(*iter);
			if (slot_impl->receiver == receiver) {
				iter = signal.slots.erase(iter);
				if (signal.slots.size() == 0) break;
			}
			else ++iter;
		}
	}

	template <typename SIGNAL, typename Receiver, typename ...Args>
	void disconnect(SIGNAL&& signal, Receiver* receiver, tan_slot_function<Receiver, Args...> slot)
	{
		for (auto iter = signal.slots.begin(); iter != signal.slots.end(); iter++) {
			TanSlotImpl<Receiver, Args...>* slot_impl = (TanSlotImpl<Receiver, Args...>*)(*iter);
			if (slot_impl->receiver == receiver && slot_impl->slot_func == slot) { signal.slots.erase(iter); break; }
		}
	}
}
#else
#include "stdlib.h"

typedef void(*tan_slot_function)();

typedef struct TanSlot {
	tan_slot_function* slot_funcs;
	int slot_nb;
}TanSlot;

typedef struct TanSignal {
	TanSlot slots;
} TanSignal;

#define tan_emit(signal, ...) { for (int i = 0; i < signal.slots.slot_nb; ++i) {\
			tan_slot_function func = signal.slots.slot_funcs[i]; func(__VA_ARGS__); } }

void init_signal(TanSignal* signal) { if (!signal) return; memset(signal, 0, sizeof(TanSignal)); }

void connect(TanSignal* signal, tan_slot_function slot_func) {
	if (!signal || !slot_func) return;

	tan_slot_function* temp_slots = (tan_slot_function*)realloc(signal->slots.slot_funcs, sizeof(tan_slot_function) * (signal->slots.slot_nb + 1));
	if (!temp_slots) return;

	signal->slots.slot_funcs = temp_slots;
	signal->slots.slot_funcs[signal->slots.slot_nb++] = slot_func;
}

void disconnect(TanSignal* signal, tan_slot_function slot_func) {
	if (!signal || !slot_func) return;

	for (int i = 0; i < signal->slots.slot_nb; ++i) {
		if (signal->slots.slot_funcs[i] == slot_func) {
			memcpy(signal->slots.slot_funcs + i, signal->slots.slot_funcs + i + 1, sizeof(TanSignal) * (signal->slots.slot_nb - i - 1));
			--signal->slots.slot_nb;
			break;
		}
	}
}
#endif

#endif // !__TANSIGNALSLOT_H__
